#!/usr/bin/env python
import base64
import getpass
import os
import select
import socket
import sys
import threading
import time
import traceback

from xpcom import components, COMException, ServerException, nsError
from xpcom._xpcom import getProxyForObject, PROXY_ASYNC, PROXY_SYNC, PROXY_ALWAYS

import paramiko

class WebOS: #WebOS Component
    _com_interfaces_ = [components.interfaces.IWebOS]
    _reg_clsid_ = "{3d374d2e-0a8e-4d0e-8f77-801431782ec9}"
    _reg_contractid_ = "@templarian.com/WebOS;1"
    _reg_desc_ = "Python Component for webOS"
    
    def __init__(self):
        # Setup observers
        self._observerSvc = components.classes["@mozilla.org/observer-service;1"].\
            getService(components.interfaces.nsIObserverService)
        self._observerSvcProxy = getProxyForObject(None,
            components.interfaces.nsIObserverService, self._observerSvc,
            PROXY_ALWAYS | PROXY_SYNC)
        self._observerSvc.addObserver(self, "webos-ssh-closed", False)
        self._output = "Python Error... OS X only error... will figure out"
    
    def observe(self, subject, topic, data):
        if(topic == "webos-ssh-closed"):
            self._callback.callback(True, self._output)
            self.unregister()
    
    def unregister(self):
        self._observerSvc.removeObserver(self, "webos-ssh-closed");
    
    def agent_auth(self, transport, username):
        agent = paramiko.Agent()
        agent_keys = agent.get_keys()
        if len(agent_keys) == 0:
            return
        
        for key in agent_keys:
            print 'Trying ssh-agent key %s' % paramiko.util.hexify(key.get_fingerprint()),
            try:
                transport.auth_publickey(username, key)
                print '... success!'
                return
            except SSHException:
                print '... nope.'
    
    def manual_auth(username, hostname):
        t.auth_password(username, '')
    
    def _handleSSH(self, hostname, port, username, password, command, input, callback):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((hostname, port))
        except Exception, e:
            print '*** Connect failed: ' + str(e)
            traceback.print_exc()
            self._observerSvcProxy.notifyObservers(self, 'webos-ssh-closed', "False")
        
        try:
            t = paramiko.Transport(sock)
            try:
                t.start_client()
            except SSHException:
                print '*** SSH negotiation failed.'
                self._observerSvcProxy.notifyObservers(self, 'webos-ssh-closed', "False")
            
            self.agent_auth(t, username)
            
            if not t.is_authenticated():
                t.auth_password(username, password)
            if not t.is_authenticated():
                print '*** Authentication failed. :('
                t.close()
                self._observerSvcProxy.notifyObservers(self, 'webos-ssh-closed', "False")
            
            chan = t.open_session()
            #chan.get_pty()
            #chan.invoke_shell()
            
            #interactive.interactive_shell(chan)
            #chan.exec_command('ls -la\n')
            if(command != ""):
                chan.exec_command(command)
            if(input != ""):
                chan.send(input)
            #chan.send('luna-send -n 1 luna://com.palm.pmradiosimulator/set_incomingcall {\"number\":\"14086177431\"}\n')
            #import win32api
            #win32api.MessageBox(0, chan.recv(9999), 'alert')
            self._output = chan.recv(9999)
            
            chan.close()
            t.close()
            
            self._observerSvcProxy.notifyObservers(self, 'webos-ssh-closed', "True")
            
            #win32api.MessageBox(0, "callback", 'alert')
            #self._callback.callback(True)
            
        except Exception, e:
            print '*** Caught exception: ' + str(e.__class__) + ': ' + str(e)
            traceback.print_exc()
            try:
                t.close()
            except:
                pass
            self._observerSvcProxy.notifyObservers(self, 'webos-ssh-closed', "False")
    
    def ssh(self, hostname, port, username, password, command, input, callback):
        self._callback = callback
        t = threading.Thread(target=self._handleSSH, args=(hostname, port, username, password, command, input, callback))
        t.setDaemon(True)
        t.start()
    
    def command(self, callback):
        runCommand(self, callback)
        import win32api
        win32api.MessageBox(0, "made it out", 'alert')
        self._observerSvcProxy.notifyObservers(self._observer, 'webos-ssh-closed', None)
        
    def runCommand(self, callback):
        username = 'root'
        hostname = 'localhost'
        port = 5522
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((hostname, port))
        except Exception, e:
            print '*** Connect failed: ' + str(e)
            traceback.print_exc()
            callback.callback(False)
        
        try:
            t = paramiko.Transport(sock)
            try:
                t.start_client()
            except SSHException:
                print '*** SSH negotiation failed.'
                callback.callback(False)
            
            self.agent_auth(t, username)
            
            if not t.is_authenticated():
                t.auth_password(username, '')
            if not t.is_authenticated():
                print '*** Authentication failed. :('
                t.close()
                callback(False)
            
            chan = t.open_session()
            #chan.get_pty()
            #chan.invoke_shell()
            
            #interactive.interactive_shell(chan)
            #chan.exec_command('ls -la\n')
            chan.exec_command('luna-send -n 1 luna://com.palm.pmradiosimulator/set_incomingcall {\\"number\\":\\"14086177431\\"}\n')
            
            #chan.send('luna-send -n 1 luna://com.palm.pmradiosimulator/set_incomingcall {\"number\":\"14086177431\"}\n')
            #import win32api
            #win32api.MessageBox(0, chan.recv(9999), 'alert')
            #print chan.recv(9999)
            
            chan.close()
            t.close()
            import win32api
            win32api.MessageBox(0, "hmm", 'alert')
            
            #self.observerService.notifyObservers(self._observer, "Topic1", "SomeData")
            
            #win32api.MessageBox(0, "callback", 'alert')
            #self._callback.callback(True)
            
        except Exception, e:
            print '*** Caught exception: ' + str(e.__class__) + ': ' + str(e)
            traceback.print_exc()
            try:
                t.close()
            except:
                pass
            callback.callback(False)
